#pragma once

#include <iostream>
#include <vector>
#include <semaphore.h>
#include "LockGuard.hpp"

// 定义默认队列大小
const int defaultSize = 5;

// 泛型环形队列类模板
template <typename T>
class RingQueue
{
private:
    // 信号量P操作，减少信号量计数，若计数<0则阻塞当前线程
    void P(sem_t &sem)
    {
        sem_wait(&sem);
    }

    // 信号量V操作，增加信号量计数，若唤醒等待的线程
    void V(sem_t &sem)
    {
        sem_post(&sem);
    }

public:
    // 构造函数，初始化环形队列
    RingQueue(int size = defaultSize)
        : _ringQueue(size), _size(size), _prodStep(0), _consStep(0)
    {
        // 初始化空间信号量，初始值为队列大小，表示初始时所有空间都是空闲的
        sem_init(&_spaceSem, 0, size);
        // 初始化数据信号量，初始值为0，表示队列初始无数据
        sem_init(&_dataSem, 0, 0);

        // 初始化生产者和消费者的互斥锁，保护各自的操作步骤
        pthread_mutex_init(&_prodMutex, nullptr);
        pthread_mutex_init(&_consMutex, nullptr);
    }

    // 向队列添加元素
    void Push(const T &item)
    {
        // 1. 减少空间信号量，尝试获取生产空间，若无空间则阻塞
        P(_spaceSem);
        {
            // 2. 加生产者锁，确保生产操作的原子性
            LockGuard lockGuard(&_prodMutex);
            // 执行实际的入队操作
            _ringQueue[_prodStep] = item;
            _prodStep++;        // 移动生产指针
            _prodStep %= _size; // 环状处理边界
        }
        V(_dataSem);
    }

    // 从队列移除元素
    void Pop(T *outItem)
    {
        // 1. 减少数据信号量，尝试获取数据，若无数据则阻塞
        P(_dataSem);
        {
            // 2. 加消费者锁，确保消费操作的原子性
            LockGuard lockGuard(&_consMutex);
            // 执行实际的出队操作
            *outItem = _ringQueue[_consStep];
            _consStep++;        // 移动消费指针
            _consStep %= _size; // 环状处理边界
        }//消费者V操作时不冲突，可以解锁 信号量的P操作（wait/减）和V操作（signal/增）都是原子操作。
        V(_spaceSem);
    }

    // 析构函数，释放资源
    ~RingQueue()
    {
        sem_destroy(&_spaceSem);
        sem_destroy(&_dataSem);

        pthread_mutex_destroy(&_prodMutex);
        pthread_mutex_destroy(&_consMutex);
    }

private:
    // 环形队列底层使用std::vector存储
    std::vector<T> _ringQueue;
    int _size; // 队列大小

    // 生产者和消费者的步进索引
    int _prodStep;
    int _consStep;

    // 信号量，管理空间和数据的可用性
    sem_t _spaceSem;
    sem_t _dataSem;

    // 互斥锁，分别保护生产者和消费者的步骤更新
    pthread_mutex_t _prodMutex;
    pthread_mutex_t _consMutex;
};